#include "tcp_sender.hh"

#include "tcp_config.hh"

#include <random>

// Dummy implementation of a TCP sender

// For Lab 3, please replace with a real implementation that passes the
// automated checks run by `make check_lab3`.

template <typename... Targs>
void DUMMY_CODE(Targs &&.../* unused */) {}

using namespace std;

//! \param[in] capacity the capacity of the outgoing byte stream
//! \param[in] retx_timeout the initial amount of time to wait before retransmitting the oldest outstanding segment
//! \param[in] fixed_isn the Initial Sequence Number to use, if set (otherwise uses a random ISN)
TCPSender::TCPSender(const size_t capacity, const uint16_t retx_timeout, const std::optional<WrappingInt32> fixed_isn)
    : _timeout(retx_timeout)
    , _isn(fixed_isn.value_or(WrappingInt32{random_device()()}))
    , _initial_retransmission_timeout{retx_timeout}
    , _stream(capacity) {}

uint64_t TCPSender::bytes_in_flight() const { return _flight_bytes; }
#include <iostream>
void TCPSender::fill_window() {
  // cerr << "fill window\n";
  // 如果远程窗口大小为0，视为1
  auto cur_win_sz = std::max(_last_win_sz, 1UL);
  while (true) {
    // 构造数据包
    TCPSegment segment;
    auto &header = segment.header();
    if (!_syn) {
      _syn = header.syn = true;
    }
    // seqno
    header.seqno = next_seqno();
    // 加载payload
    auto payload_sz = std::min(TCPConfig::MAX_PAYLOAD_SIZE, cur_win_sz - _flight_bytes - header.syn);
    std::string payload = _stream.read(payload_sz);

    /**
     * 设置fin的条件
     * 1. 从没发过fin; fin会占用序列号导致bytes_in_flight非空, 前个fin包是会触发重传的，并不需要主动再次发fin
     * 2. 输入流eof
     * 3. fin占用一个序列号, 所以fin必须能放在窗口中
     */
    if (!_fin && _stream.eof() && payload.size() + _flight_bytes < cur_win_sz) {
      _fin = header.fin = true;
    }
    segment.payload() = std::move(payload);
    // 没有任何数据，停止数据包的发送
    if (segment.length_in_sequence_space() == 0) {
      break;
    }
    // 开启定时器, 计划重传
    if (_outgoing_queue.empty()) {
      _timeout = _initial_retransmission_timeout;
      _timeout_wait = 0;
    }
    // 发送
    _segments_out.push(segment);
    // 追踪
    auto length = segment.length_in_sequence_space();
    _flight_bytes += length;
    // _outgoing_map.emplace(_next_seqno, segment);
    _outgoing_queue.emplace(_next_seqno, segment);
    // 更新 abs_seqno
    _next_seqno += length;
    // 如果设置了fin，直接退出
    if (header.fin) {
      break;
    }
  }
}

//! \param ackno The remote receiver's ackno (acknowledgment number)
//! \param window_size The remote receiver's advertised window size
//! \returns `false` if the ackno appears invalid (acknowledges something the TCPSender hasn't sent yet)
bool TCPSender::ack_received(const WrappingInt32 ackno, const uint16_t window_size) {
  // std::cerr << "--- ack_received ---\n";
  // std::cerr << _next_seqno << " " << ackno << "\n";
  auto abs_seqno = unwrap(ackno, _isn, _next_seqno);
  // ackno 无效
  if (abs_seqno > _next_seqno) {
    return false;
  }
  for (; !_outgoing_queue.empty();) {
    const auto &front = _outgoing_queue.front();
    const auto &segment = front.second;
    // std::cerr << front.first << " " << segment.length_in_sequence_space() << " " << abs_seqno << "\n";
    if (front.first + segment.length_in_sequence_space() <= abs_seqno) {
      _flight_bytes -= segment.length_in_sequence_space();
      _outgoing_queue.pop();
      // 新的数据包被接受，清空超时时间
      _timeout = _initial_retransmission_timeout;
      _timeout_wait = 0;
    } else {
      // 当前数据包未被确认, 那么之后的数据包不用检查
      break;
    }
  }
  _consecutive_retransmissions_count = 0;
  // 更新window size
  _last_win_sz = window_size;
  // 填充数据
  fill_window();
  return true;
}

//! \param[in] ms_since_last_tick the number of milliseconds since the last call to this method
void TCPSender::tick(const size_t ms_since_last_tick) {
  // 更新重传已等待时间
  _timeout_wait += ms_since_last_tick;
  if (_outgoing_queue.empty()) {
    return;
  }
  if (_timeout_wait >= _timeout) {
    const auto &front = _outgoing_queue.front();
    // 窗口大小不为0
    if (_last_win_sz > 0) {
      _timeout *= 2;
    }
    _timeout_wait = 0;
    // 再次发送
    _segments_out.push(front.second);
    // 连续重传次数加1
    ++_consecutive_retransmissions_count;
  }
}

unsigned int TCPSender::consecutive_retransmissions() const { return _consecutive_retransmissions_count; }

void TCPSender::send_empty_segment() {
  TCPSegment segment;
  segment.header().seqno = next_seqno();
  _segments_out.push(segment);
}
